﻿using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;


namespace KunURP
{
    public class BokenBlur : ScriptableRendererFeature
    {
        [System.Serializable]
        public class Setting
        {
            public RenderPassEvent passEvent = RenderPassEvent.AfterRenderingTransparents;//默认插到透明完成后
            public Material material;
            [Range(3, 500)]
            public int loopCount = 50;
            [Range(1, 10)]
            public float rtDownScaling = 2;
            [Range(0, 0.5f)]
            public float blurSmoothness = 0.5f;
            [Range(0.1f, 10f)]
            public float blurRadius = 1f;
            public float nearDistance = 0;
            public float farDistance = 10000000;
        }

        public Setting m_Setting = new Setting();

        class CustomRenderPass : ScriptableRenderPass
        {
            public const int MaxLevel = 16;

            public Material material;
            public int loopCount = 50;
            public float rtDownScaling = 2;
            public float blurSmoothness = 0.5f;
            public float blurRadius = 1f;
            public float nearDistance = 0;
            public float farDistance = 10000000;

            FilterMode passFilterMode{ get; set; }//图像的模式
            RenderTargetIdentifier passSource{ get; set; }//源图像,目标图像
            string passTag;

            static class ShaderIDs
            {
                internal static readonly int SourceTex = Shader.PropertyToID("_SourceTex");
                internal static readonly int BlurTex = Shader.PropertyToID("_BlurTex");
                internal static readonly int BlurSmoothness = Shader.PropertyToID("_BlurSmoothness");
                internal static readonly int BlurRadius = Shader.PropertyToID("_BlurRadius");
                internal static readonly int NearDistance = Shader.PropertyToID("_NearDistance");
                internal static readonly int FarDistance = Shader.PropertyToID("_FarDistance");
                internal static readonly int LoopCount = Shader.PropertyToID("_LoopCount");
            }

            public CustomRenderPass(string tag)
            {
                this.passTag = tag;
            }

            public void Setup(RenderTargetIdentifier passSource)
            {
                this.passSource = passSource;
            }
            
            public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
            {
                CommandBuffer cmd = CommandBufferPool.Get(this.passTag);
                RenderTextureDescriptor opaqueDesc = renderingData.cameraData.cameraTargetDescriptor;
                int width = (int)(opaqueDesc.width / this.rtDownScaling);
                int height = (int)(opaqueDesc.height / this.rtDownScaling);
                this.material.SetFloat(ShaderIDs.BlurSmoothness, this.blurSmoothness);
                this.material.SetFloat(ShaderIDs.BlurRadius, this.blurRadius);
                this.material.SetFloat(ShaderIDs.LoopCount, this.loopCount);
                this.material.SetFloat(ShaderIDs.NearDistance, this.nearDistance);
                this.material.SetFloat(ShaderIDs.FarDistance, this.farDistance);
                cmd.GetTemporaryRT(ShaderIDs.BlurTex, width, height, 0, this.passFilterMode);
                cmd.GetTemporaryRT(ShaderIDs.SourceTex, opaqueDesc);
                cmd.CopyTexture(this.passSource, ShaderIDs.SourceTex);
                cmd.Blit(this.passSource, ShaderIDs.BlurTex, this.material, 0);
                cmd.Blit(ShaderIDs.BlurTex, this.passSource, this.material, 1);
                // cmd.CopyTexture(ShaderIDs.BlurTex, this.passSource);
                context.ExecuteCommandBuffer(cmd);
                cmd.ReleaseTemporaryRT(ShaderIDs.BlurTex);
                cmd.ReleaseTemporaryRT(ShaderIDs.SourceTex);
                CommandBufferPool.Release(cmd);
            }

        }

        CustomRenderPass m_ScriptablePass;

        public override void Create()
        {
            this.m_ScriptablePass = new CustomRenderPass(name);
            this.m_ScriptablePass.renderPassEvent = this.m_Setting.passEvent;
            this.m_ScriptablePass.material = this.m_Setting.material;
            this.m_ScriptablePass.loopCount = this.m_Setting.loopCount;
            this.m_ScriptablePass.blurSmoothness = this.m_Setting.blurSmoothness;
            this.m_ScriptablePass.blurRadius = this.m_Setting.blurRadius;
            this.m_ScriptablePass.rtDownScaling = this.m_Setting.rtDownScaling;
            this.m_ScriptablePass.nearDistance = this.m_Setting.nearDistance;
            this.m_ScriptablePass.farDistance = this.m_Setting.farDistance;
        }

        // Here you can inject one or multiple render passes in the renderer.
        // This method is called when setting up the renderer once per-camera.
        public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
        {
            if (this.m_Setting.material != null)
            {
                this.m_ScriptablePass.Setup(renderer.cameraColorTarget);
                renderer.EnqueuePass(this.m_ScriptablePass);
            }
        }
    }

}
